/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c) 2002, GeoVISTA Center
 * Licensed under Simplified BSD License
 * This library is developed and distributed for free usage,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * You can redistribute and/or modify it under the terms of the
 * Simplified BSD License
 *
 *
 *
 *
 *
 *
 *
 * @original author: jin Chen 
 * @author: jin Chen 
 * @date: Nov 12, 2007$
 * @version: 1.0
 */
package edu.psu.geovista.app.vit.pub.components.sts;

import edu.psu.geovista.app.vit.pub.utils.VitUtils;

import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import java.awt.*;
import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.Vector;

public class MyTableModel extends AbstractTableModel {      // 
    public static final String DEFAULT_SHP_COLUMN_NAME="shp";
    public static final String DEFAULT_DUMMY_COLUMN_NAME="dummyData";

    public static enum EmptyStringPolicy{ EMPTY(""),ZERO("0");
        String value; // a string value to use when find empty value for numeric value

        EmptyStringPolicy(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }
    public static final int NULL_INT = -1 * Integer.MAX_VALUE;// 

    Vector<Vector> dataVector =new Vector();  //each element is an vector
    Vector<Object> columnIdentifiers =new Vector();
    protected String[] rowNameColumns;// 
    int[] idindexs=new int[]{0}; // 


    public MyTableModel() {
    }

    public MyTableModel(TableModel tm) {
        this.add(tm);
    }

    /*******************************************************************************************************
     *                column
     *******************************************************************************************************/
    public void addColumn(Object colId, Vector column){
        this.addColumn(colId,column,true);
    }

    /**
     *
     * @param colId
     * @param column
     * @param equalRowCount   
     */
    public void addColumn(Object colId, Vector column, boolean equalRowCount){
        //make sure value is an array
        if(equalRowCount) {
            int rowCount = this.getRowCount();
            if (rowCount>0&&column.size()!=rowCount){
                new IllegalArgumentException(this.getClass().getName() +" is array with length "+column.size()+" != current row count "+rowCount);
            }
        }
        //make sure no duplicate column id
        int colindex = this.getColumnIndexById(colId);
        if(colindex>=0){//the column id exist
            new IllegalArgumentException(this.getClass().getName() +" the column id "+ colId + "already exist!");
        }
        synchronized(this){
            columnIdentifiers.add(colId);
            dataVector.add(column);
        }
        fireTableStructureChanged();
    }


    public void removeColumn(int index){
        synchronized(this){
            columnIdentifiers.remove(index);
            dataVector.remove(index);
        }
        fireTableStructureChanged();
    }


    public Vector getColumn(Object colId){
        int col = getColumnIndexById(colId);
        if(col>=0)
            return (Vector) this.dataVector.get(col);
        else return new Vector();
    }


   


    public String getColumnName(int column) {
        return this.columnIdentifiers.get(column).toString() ;  //To change body of implemented methods use File | Settings | File Templates.
    }
    public String[] getColumnNames() {
        return VitUtils.convert2StringArrayNoNull(this.columnIdentifiers);
    }
   


    /*******************************************************************************************************
     *                values
     *******************************************************************************************************/

    public void setValueAt(Object aValue, int row, int column) {
        Vector colVector = (Vector)dataVector.elementAt(column);
        colVector.setElementAt(aValue, row);
        fireTableCellUpdated(row, column);
    }
    /*******************************************************************************************************
     *                get values
     *******************************************************************************************************/



    public Object getValueAt(int row, int column) {
        Vector acolumn = (Vector) this.dataVector.get(column);
        return acolumn.get(row);

    }
    public Object getValueAt(int row, Object columnId){
        int col = this.getColumnIndexById(columnId);
        return this.getValueAt(row,col);
    }


    /**
     * @param valueColumnId  return value in this column
     * @param checkColumnId  check the value on this column, see if it equal to <value>
     * @param value
     * @return
     */
    public Object getValue(Object  valueColumnId,Object  checkColumnId, Object value){

        // ArrayList myvalues=new ArrayList();

            Vector values = this.getColumn(checkColumnId);
            for (int i=0;i<values.size() ;i++){
                if(values.get(i).equals(value)){
                    Object v = this.getValueAt(i, valueColumnId);
                    return v;
                }
            }

        return null;

    }


    /**
     *
     * @param row
     * @return      a copy of the rowdata
     */
    public Vector getRowValues(int row){
        int columnCount = this.getColumnCount();
        Vector arow=new Vector(columnCount);
        for (int col =0;col <columnCount ;col++){
            Vector column = (Vector) dataVector.get(col);
            if(column!=null&&column.size() >0) {
                Object avalue = column.get(row);
                arow.add(avalue );
            }
            else{
                arow.add(null);
            }
        }
        return arow;
    }

    /**
     *  
     *  
     * Note: this method has a high computational cost
     * @param colId
     * @param value
     * @return
     */
    public int getRowIndex(Object colId, Object value ){
        Vector vector = this.getColumn(colId);
        int rowIndex = vector.indexOf(value);
        return rowIndex;
    }




    /*******************************************************************************************************
     *                get indexs
     *******************************************************************************************************/
    public int getColumnIndexById(Object id){
        int index=0;
        for (Iterator iterator = columnIdentifiers.iterator(); iterator.hasNext();) {
            Object aid = iterator.next();
            if(aid.equals(id) ){
                return index;
            }
            index++;
        }
        return -1;
    }






    /*******************************************************************************************************
     *                AppDataModel
     *******************************************************************************************************/
    public int getRowCount() {
        if(this.dataVector ==null||dataVector.size() <=0) return 0;//no data yet
        Vector column = (Vector) dataVector.get(0);
        int len = column.size() ;
        return len;  //To change body of implemented methods use File | Settings | File Templates.
    }

    /**
     *  
     * @return
     */
    public int getColumnCount() {
      
        return (columnIdentifiers ==null)?0: columnIdentifiers.size();
    }


    /**
     * 
     * @param rawData
     */
    public void feedData(Object[] rawData) {
        Object[] colIds = (Object[]) rawData[0];
        for (int i=0;i<colIds.length ;i++){
            Object colid = colIds[i];
            Object column = rawData[i + 1];
            if(colid!=null&&colid.toString().trim().length() >0)
                addColumn(colid,column);
            else{
                System.err.println(this.getClass().getSimpleName()+ ".feedData(): Column "+i+ " has an empty column id, hence ignore the column");
            }
        }

    }

    /**
     *
     * @param colid
     * @param colvalue    
     */
    public void addColumn(Object colid, Object colvalue){
        int[] intarray=new int[0];
        double[] dbarray=new double[0];
        boolean[] blarray=new boolean[0];
        String[] strarray=new String[0];
        Shape[] shparray=new Shape[0];
        if(colvalue.getClass().isArray()){
            new IllegalArgumentException(this.getClass().getName() +" addColumn(Object colid, Object colvalue) expect an array. ");
        }
        int len = Array.getLength(colvalue);
        Vector column=new Vector(len );
        if(intarray.getClass().isAssignableFrom(colvalue.getClass() )){
            intarray=(int[]) colvalue;
            for (int i=0;i<intarray.length ;i++){
                column.add(intarray[i]);
            }
        }
        else if (dbarray.getClass().isAssignableFrom(colvalue.getClass() )){
            dbarray=(double[]) colvalue;
            for (int i=0;i<dbarray.length ;i++){
                column.add(dbarray[i]);
            }
        }
        else if (blarray.getClass().isAssignableFrom(colvalue.getClass() )){
            blarray=(boolean[]) colvalue;
            for (int i=0;i<blarray.length ;i++){
                column.add(blarray[i]);
            }
        }
        else if (strarray.getClass().isAssignableFrom(colvalue.getClass() )){
            strarray=(String[]) colvalue;
            for (int i=0;i<strarray.length ;i++){
                column.add(strarray[i]);
            }
        }
        else if (shparray.getClass().isAssignableFrom(colvalue.getClass() )){
            shparray=(Shape[]) colvalue;
            for (int i=0;i<shparray.length ;i++){
                column.add(shparray[i]);
            }
        }
        else{
            for (int i=0;i<len;i++){
                Object element = Array.get(colvalue, i);
                column.add(element);
            }
        }
        this.addColumn(colid,column);
    }

    public Vector<Vector> getDataVector() {
        return dataVector;
    }

    public void setDataVector(Vector<Vector> dataVector) {
        this.dataVector = dataVector;
    }

    /*******************************************************************************************************
     *                getter/setter
     *******************************************************************************************************/



    public static DefaultTableModel getTableModel(MyTableModel colmodel){
        DefaultTableModel tm=new DefaultTableModel();
        String[] colnames = colmodel.getColumnNames();

        for (int i=0;i<colnames.length ;i++){
            Vector acol = colmodel.getColumn(colnames[i]);
            tm.addColumn(colnames[i],acol);
        }
        return tm;
    }
    public void add(TableModel tm){


        int colcount = tm.getColumnCount();
        int rowcount = tm.getRowCount();

        for (int j=0;j<colcount;j++){
            String colname = tm.getColumnName(j);
            Vector col=new Vector(rowcount);
            for (int i=0;i<rowcount;i++){
                Object v = tm.getValueAt(i, j);
                col.add(v);
            }
            this.addColumn(colname,col);
        }
    }

  

}
